/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.model.command;

import static com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil.getCoveredBys;
import static com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil.getCovereds;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.Lifeline;

/**
 * Takes an Interaction Fragments and a list of Lifelines and ensures that all
 * the lifelines are covered by the specified fragment.
 * 
 * <p>
 * The following attributes must be set before the command can be executed:
 * </p>
 * 
 * <ul>
 * <li>Fragment
 * <li>Covered (must be non-null, but can be an empty list)
 * </ul>
 * 
 * @author frankd@ifi.uio.no
 */
public class CoverCommand extends Command {

	private InteractionFragment fragment;
	private List<LifelinePosition> oldCovered, newCovered;

	public CoverCommand() {
	}

	public CoverCommand(final InteractionFragment fragment,
			final List<LifelinePosition> covered) {
		setFragment(fragment);
		setCovered(covered);
	}

	public void setFragment(final InteractionFragment fragment) {
		this.fragment = fragment;
	}

	public void setCovered(final List<LifelinePosition> covered) {
		this.newCovered = covered;
	}

	@Override
	public void execute() {
		oldCovered = new ArrayList<LifelinePosition>(getCovereds(fragment)
				.size());
		for (Lifeline lifeline : getCovereds(fragment)) {
			oldCovered.add(new LifelinePosition(lifeline, lifeline
					.getCoveredBys().indexOf(fragment)));
		}
		// oldCovered = fragment.getCovereds();
		doCover(newCovered);
	}

	@Override
	public void undo() {
		doCover(oldCovered);
		oldCovered = null;
	}

	@Override
	public void redo() {
		this.execute();
	}

	private void doCover(List<LifelinePosition> list) {
		// First remove all lifelines that are no longer covered. This has to
		// be done because other parts of the code expect single-covering
		// fragments to cover at most one lifeline.
		List<Lifeline> obsolete = new ArrayList<Lifeline>(getCovereds(fragment));
		for (LifelinePosition lp : list)
			obsolete.remove(lp.getLifeline());
		getCovereds(fragment).removeAll(obsolete);
		// fragment.getCovereds().clear();

		for (LifelinePosition lp : list) {
			int oldIndex = getCoveredBys(lp.getLifeline()).indexOf(fragment);
			if (oldIndex >= 0) {
				if (oldIndex != lp.getPosition())
					lp.getLifeline().getCoveredBys().move(lp.getPosition(),
							oldIndex);
			} else if (oldIndex == -1)
				getCoveredBys(lp.getLifeline()).add(lp.getPosition(), fragment);
		}

		// Debugging
		/*
		 * StringBuffer covering = new StringBuffer(); for (Lifeline l : (List<Lifeline>)
		 * fragment.getCovereds()) covering.append(l.getName() + "(" +
		 * l.getCoveredBys().indexOf(fragment) + ") ");
		 */
	}

	@Override
	public void dispose() {
		fragment = null;
		oldCovered = null;
		newCovered = null;
	}
}
